
function [model, qualityOverValidation, config] = learnConfiguredCRF(trainingdata, validationdata, config)

    % Extract unary features
    fprintf('Computing unary features\n');
    % Compute unary features on training data
    [trainingdata.unaryFeatures, config.features.unary.unaryDimensionality, trainingdata.numberOfPixels, trainingdata.masks, trainingdata.filenames] = extractFeatures(strcat(config.training_data_path, filesep, 'images'), ...
                                                                                              strcat(config.training_data_path, filesep, 'masks'), ...
                                                                                              config, ...
                                                                                              config.features.unary.unaryFeatures, ...
                                                                                              true);
    % Compute unary features on validation data
    [validationdata.unaryFeatures, ~, ~, validationdata.masks, validationdata.filenames] = extractFeatures(strcat(config.validation_data_path, filesep, 'images'), ...
                                                   strcat(config.validation_data_path, filesep, 'masks'), ...
                                                   config, ...
                                                   config.features.unary.unaryFeatures, ...
                                                   true);

    % Compute pairwise features on training data
    % Extract pairwise features
    [pairwisefeatures, config.features.pairwise.pairwiseDimensionality, ~, ~, ~] = extractFeatures(strcat(config.training_data_path, filesep, 'images'), ...
                                                                                          strcat(config.training_data_path, filesep, 'masks'), ...
                                                                                          config, ...
                                                                                          config.features.pairwise.pairwiseFeatures, ...
                                                                                          false);
    config.features.pairwise.pairwiseDeviations = config.features.pairwise.pairwiseDeviations(generateFeatureFilter(config.features.pairwise.pairwiseFeatures, config.features.pairwise.pairwiseFeaturesDimensions));
    trainingdata.pairwiseKernels = getPairwiseFeatures(pairwisefeatures, config.features.pairwise.pairwiseDeviations);

    % Compute pairwise features on validation data
    pairwisefeatures = extractFeatures(strcat(config.validation_data_path, filesep, 'images'), ...
                                       strcat(config.validation_data_path, filesep, 'masks'), ...
                                       config, ...
                                       config.features.pairwise.pairwiseFeatures, ...
                                       false);
    validationdata.pairwiseKernels = getPairwiseFeatures(pairwisefeatures, config.features.pairwise.pairwiseDeviations);

    % Filter the value of theta_p
    config.theta_p.finalValues = ...
        config.theta_p.values(generateFeatureFilter(config.features.pairwise.pairwiseFeatures, config.features.pairwise.pairwiseFeaturesDimensions));

    % Train with this configuration and return the model
    [model, qualityOverValidation, config] = learnCRFPotentials(config, trainingdata, validationdata);

end